﻿#pragma once

#define GLM_ENABLE_EXPERIMENTAL

#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "SourceCode/Base/UUID.h"
#include "SourceCode/Renderer/Texture.h"
#include "SourceCode/Scene/SceneCamera.h"

namespace Hazal
{
	struct SIDComponent
	{
		CUUID m_id;

		SIDComponent() = default;
		SIDComponent(const SIDComponent&) = default;
		SIDComponent(CUUID id) : m_id(id) {}
	};

	struct STransformComponent
	{
		glm::vec3 m_vecTranslation = {0.0f, 0.0f, 0.0f };
		glm::vec3 m_vecRotation = { 0.0f, 0.0f, 0.0f };
		glm::vec3 m_vecScale = { 1.0f, 1.0f, 1.0f };

		STransformComponent() = default;
		STransformComponent(const STransformComponent&) = default;
		STransformComponent(const glm::vec3& vecTranslation) : m_vecTranslation(vecTranslation) {}

		glm::mat4 GetTransform()
		{
			glm::mat4 matRotation = glm::mat4_cast(glm::quat(m_vecRotation)) * glm::mat4(1.0f);

			return glm::translate(glm::mat4(1.0f), m_vecTranslation) * matRotation * glm::scale(glm::mat4(1.0f), m_vecScale);
		}
	};

	struct STagComponent
	{
		std::string m_strTag;

		STagComponent() = default;
		STagComponent(const STagComponent&) = default;
		STagComponent(const std::string strTag) : m_strTag(strTag) {}
	};

	struct SSpriteRendererComponent
	{
		glm::vec4 m_vecColor{1.0f, 1.0f, 1.0f, 1.0f };
		Ref<CTexture2D> m_texture;
		float m_fTilingfFactor = 1.0f;

		SSpriteRendererComponent() = default;
		SSpriteRendererComponent(const SSpriteRendererComponent&) = default;
		SSpriteRendererComponent(const glm::vec4& vecColor) : m_vecColor(vecColor) {}

		operator const glm::vec4& () const { return m_vecColor; }
		operator glm::vec4& () { return m_vecColor; }
	};

	struct SCircleRendererComponent
	{
		glm::vec4 m_vecColor{ 1.0f, 1.0f, 1.0f, 1.0f };
		float m_fRadius = 0.5f;
		float m_fThickness = 1.0f;
		float m_fFade = 0.005f;

		SCircleRendererComponent() = default;
		SCircleRendererComponent(const SCircleRendererComponent&) = default;
		SCircleRendererComponent(const glm::vec4& vecColor) : m_vecColor(vecColor) {}

	};

	struct SCameraComponent
	{
		Hazal::CSceneCamera m_Camera;
		bool m_bPrimary = true;				///< 是否主相机标识
		bool m_bFixedAspectRadio = false;	///< 是否固定纵横比

		SCameraComponent() = default;
		SCameraComponent(const SCameraComponent&) = default;
	};

	class CScriptableEntity;
	struct SNativeScriptComponent
	{
		CScriptableEntity* m_pInstance = nullptr;

		CScriptableEntity* (*InstantiateScript)();
		void (*DestroyScript)(SNativeScriptComponent*);

		template<typename T>
		void Bind()
		{
			InstantiateScript = []() { return static_cast<CScriptableEntity*>(new T()); };
			DestroyScript = [](SNativeScriptComponent* pNsc) { delete pNsc->m_pInstance; pNsc->m_pInstance = nullptr; };
		}
	};

	/// <summary>
	/// Describe a 2d rigid body
	/// </summary>
	struct SRigidBody2DComponent
	{
		enum class EBodyType
		{
			Static = 0,		///< A body which always keeps in static
			Dynamic,		///< A body which can move
			Kinematic,		///< TODO
		};
		EBodyType m_eBodyType = EBodyType::Static;
		bool m_bFixedRotation = false;
		void* m_pRunTimeBody = nullptr;	///< Storage for runtime

		SRigidBody2DComponent() = default;
		SRigidBody2DComponent(const SRigidBody2DComponent&) = default;
	};

	/// <summary>
	/// Describe a 2d collider
	/// </summary>
	struct SCollider2DComponent
	{
		glm::vec2 m_v2Offset = { 0.0f, 0.0f };	///< 碰撞盒距离刚体质心的偏移(default = 0)
		glm::vec2 m_v2Size = { 0.5f, 0.5f };	///< 碰撞盒大小(Default = {0.5, 0.5})

		float m_fDensity = 1.0f;				///< 密度(default = 1.0f)
		float m_fFriction = 0.5f;				///< 摩擦力(default = 0.5f)

		float m_fRestitution = 0.0f;
		float m_fRestitutionThreshold = 0.5f;

		SCollider2DComponent() = default;
		SCollider2DComponent(const SCollider2DComponent&) = default;
	};
}